/*
 * ProfileGenerator_test.cpp
 *
 *  Created on: 8 gru 2013
 *      Author: malwina.kowalczyk
 */

#include "ProfileGenerator.hpp"
#include "Assertions.hpp"
#include "gtest_wrapper.hpp"

namespace generator
{

dna::genotype createGenotype(char first, char second) {
	return std::make_pair(dna::allel(first), dna::allel(second));
}

dna::genotypeSet createGenotypeSet(dna::genotype g1, dna::genotype g2) {
	dna::genotypeSet set(2);
	set = { g1, g2};
	return set;
}


TEST(ProfileGenerator, shouldGetProperProfilePairForCurrentIndex)
{
	//given
	// prepare genotypes
	dna::genotype g1 =createGenotype('A', 'B');
	dna::genotype g2 = createGenotype('A', 'C');
	dna::genotype g3 = createGenotype('B', 'C');

	dna::genotype g4 = createGenotype('X', 'Y');
	dna::genotype g5 = createGenotype('X', 'Z');

	//prepare genotype sets
	dna::genotypeSet s1 = createGenotypeSet(g1, g2);
	dna::genotypeSet s2 = createGenotypeSet(g3, g2);
	dna::genotypeSet s3 = createGenotypeSet(g4, g5);

	// prepare markers
	std::list<dna::genotypeSet> m1(2);
	m1 = {s1, s2};
	std::list<dna::genotypeSet> m2(1);
	m2 = {s3};

	ProfileGenerator generator;
	std::list<std::list<dna::genotypeSet>> markersArray(2);
	markersArray = {m1, m2};


	std::vector<std::list<dna::profile>::const_iterator> indexes;
	indexes.push_back(markersArray.front().begin());
	indexes.push_back(markersArray.back().begin());

	std::vector<std::list<dna::profile>::const_iterator> indexes2;
	std::list<dna::profile>::iterator it;
	it = markersArray.front().begin();
	it++;
	indexes2.push_back(it);
	indexes2.push_back(markersArray.back().begin());

	//begin
	std::vector<dna::profile>  profile  = generator.getProfileTupleForCurrentIndex(markersArray, indexes,2);
	std::vector<dna::profile>  profile2  = generator.getProfileTupleForCurrentIndex(markersArray, indexes2,2);

	//then
	ASSERT_EQ(2, profile.size())<< "Wrong profile count for two people!";
	assertProfile(profile[0], "(A,B)(X,Y)");
	assertProfile(profile[1], "(A,C)(X,Z)");

	ASSERT_EQ(2, profile2.size())<< "Wrong profile count for two people!";
	assertProfile(profile2[0], "(B,C)(X,Y)");
	assertProfile(profile2[1], "(A,C)(X,Z)");
}

TEST(ProfileGenerator, shouldGetProperTripleForCurrentIndex)
{
	//given
	// prepare genotypes
	dna::genotype g1 =createGenotype('A', 'B');
	dna::genotype g2 = createGenotype('A', 'C');
	dna::genotype g3 = createGenotype('B', 'C');

	dna::genotype g4 = createGenotype('X', 'Y');
	dna::genotype g5 = createGenotype('X', 'Z');

	//prepare genotype sets
	dna::genotypeSet s1(3);
	s1 = {g1, g2, g1};
	dna::genotypeSet s2(3);
	s2={g3, g2, g1};
	dna::genotypeSet s3(3);
	s3={g4, g5, g5};

	// prepare markers
	std::list<dna::genotypeSet> m1(2);
	m1 = {s1, s2};
	std::list<dna::genotypeSet> m2(1);
	m2 = {s3};

	ProfileGenerator generator;
	std::list<std::list<dna::genotypeSet>> markersArray(2);
	markersArray = {m1, m2};

	// {1, 0};

	std::vector<std::list<dna::profile>::const_iterator> indexes2;
	std::list<dna::profile>::iterator it;
	it = markersArray.front().begin();
	it++;
	indexes2.push_back(it);
	indexes2.push_back(markersArray.back().begin());
	
	//when
	std::vector<dna::profile>  profile = generator.getProfileTupleForCurrentIndex(markersArray, indexes2, 3);

	// then
	ASSERT_EQ(3, profile.size())<< "Wrong profile count for three people!";
	assertProfile(profile[0], "(B,C)(X,Y)");
	assertProfile(profile[1], "(A,C)(X,Z)");
	assertProfile(profile[2], "(A,B)(X,Z)");
}

class VectorOutput : public generator::ProfileOutput
{
public:
	VectorOutput(std::list<std::vector<dna::profile>>& result) : result_(result){};
	virtual void put(const std::vector<dna::profile>& profile)
	{
		result_.push_back(profile);
	}
private:
	std::list<std::vector<dna::profile>>& result_;
};

TEST(ProfileGenerator, shouldGenerateAll)
{
	// given
	// prepare genotypes
	dna::genotype g1 =createGenotype('A', 'B');
	dna::genotype g2 = createGenotype('A', 'C');
	dna::genotype g3 = createGenotype('B', 'C');

	dna::genotype g4 = createGenotype('X', 'Y');
	dna::genotype g5 = createGenotype('X', 'Z');

	dna::genotype g6 = createGenotype('K', 'L');
	dna::genotype g7 = createGenotype('K', 'M');

	// prepare genotype sets
	dna::genotypeSet s1(3);
	s1 = {g1, g2, g1};
	dna::genotypeSet s2(3);
	s2={g3, g2, g1};
	dna::genotypeSet s3(3);
	s3={g4, g5, g5};
	dna::genotypeSet s4(3);
	s4={g6, g7, g6};
	dna::genotypeSet s5(3);
	s5={g7, g7, g6};

	// prepare markers
	std::list<dna::genotypeSet> m1(2);
	m1 = {s1, s2};
	std::list<dna::genotypeSet> m2(1);
	m2 = {s3};
	std::list<dna::genotypeSet> m3(2);
	m3 = {s4, s5};


	ProfileGenerator generator;
	std::list<std::list<dna::genotypeSet>> markersArray(3);
	markersArray = {m1, m2, m3};

	//when
	std::list<std::vector<dna::profile>>  result;
	generator.generateAll(markersArray, generator::outputPtr(new VectorOutput(result)), 3);


#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wall"
#pragma GCC diagnostic ignored "-Wwrite-strings"
	// then
	char* r[4][3] = 
	{{"(A,B)(X,Y)(K,L)","(A,C)(X,Z)(K,M)", "(A,B)(X,Z)(K,L)"},
	{"(B,C)(X,Y)(K,L)","(A,C)(X,Z)(K,M)", "(A,B)(X,Z)(K,L)"},
	{"(A,B)(X,Y)(K,M)", "(A,C)(X,Z)(K,M)", "(A,B)(X,Z)(K,L)"}, 
	{"(B,C)(X,Y)(K,M)", "(A,C)(X,Z)(K,M)", "(A,B)(X,Z)(K,L)"}};
#pragma GCC diagnostic pop

	ASSERT_EQ(4, result.size())<< "Wrong triple count";
	std::list<std::vector<dna::profile>>::iterator result_it;
	size_t i=0;
	for (result_it = result.begin(); result_it!= result.end(); ++result_it)
	{	
		std::vector<dna::profile> res = *result_it;
		for (size_t j=0; j< res.size(); j++) {
		assertProfile(res[j], r[i][j]);
		}
		i++;
	}
}


} /* namespace generator */
